package musicthread;

import client.ClientPlayer;
import gameframe.Chess;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;

/**
 * @author Hsu琛君珩
 * @ClassName:MusicThread
 * @date 2023-12-22
 * @apiNote
 * @Version: v1.0
 */

/**
 * 音效播放类，用于背景音乐和棋子放置音效。
 * 该类使用单例模式确保全局只有一个音效播放实例。
 */
public class MusicThread {

    private boolean isPlayingMusic = false;

    private static MusicThread instance; // 单例实例

    // 音乐文件的路径
    private static String bgmPath = "music/dushen.wav"; // 背景音乐文件路径
    private static String chessMusic = "music/putchess.wav"; // 棋子放置音效文件路径

    /**
     * 获取音效播放器的单例实例。
     *
     * @return 单例实例
     */
    public static MusicThread getInstance() {
        if (instance == null) {
            instance = new MusicThread();
        }
        return instance;
    }

    /**
     * 启动背景音乐播放线程。
     * 仅在玩家为白棋方时播放背景音乐，减少资源占用。
     */
    public void startBackgroundMusic() {
        if (ClientPlayer.getInstance().getChessColor() != Chess.WHITE) {
            // 如果玩家不是白棋，不播放背景音乐
            return;
        }
        isPlayingMusic = true; // 开始播放音乐
        System.out.println("开始播放背景音乐");
        new Thread(() -> {
            while (ClientPlayer.getInstance().isGaming() && isPlayingMusic) {
                // 循环播放背景音乐，直到游戏结束或被外部命令停止
                playMusic(bgmPath);
            }
        }).start();
    }

    public void stopBackgroundMusic() {
        isPlayingMusic = false; // 停止播放音乐
    }

    /**
     * 播放棋子放置音效。
     * 每次调用将在新线程中播放一次音效。
     */
    public void playChessSound() {
        new Thread(() -> {
            playMusic(chessMusic);
        }).start();
    }

    /**
     * 播放音乐的通用方法。
     * 此方法用于播放指定路径的音频文件。它首先尝试打开音频文件并创建输入流，然后设置音频格式和缓冲区以播放音频。
     * 此方法还包含一个音量控制机制，允许调整播放音量。最后，它循环读取音频数据并播放，直到音频播放完毕。
     *
     * @param musicPath 音乐文件路径，它指向需要播放的音频文件。
     */
    private static void playMusic(String musicPath) {
        try {
            // 打开音频输入流
            AudioInputStream ais = AudioSystem.getAudioInputStream(new File(musicPath));
            AudioFormat aif = ais.getFormat();
            final SourceDataLine sdl;
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, aif);
            sdl = (SourceDataLine) AudioSystem.getLine(info);
            sdl.open(aif);
            sdl.start();

            // 设置音量控制
            FloatControl fc = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
            float volume = 0.001f; // 设置音量为0.5，可根据需要调整
            // 转换音量为分贝值，以便设置
            float dB = (float) (Math.log(volume == 0.0 ? 0.0001 : volume) / Math.log(10.0) * 20.0);
            fc.setValue(dB);

            // 读取音频数据并播放
            int nByte = 0;
            final int SIZE = 1024 * 64; // 缓冲区大小
            byte[] buffer = new byte[SIZE];
            while (true) {
                nByte = ais.read(buffer, 0, SIZE);
                if (nByte == -1) {
                    // 音频数据读取完毕
                    break;
                }
                sdl.write(buffer, 0, nByte);
            }
            sdl.stop(); // 停止播放
        } catch (UnsupportedAudioFileException uafe) {
            uafe.printStackTrace();
            System.out.println("不支持的音频文件格式：" + musicPath);
        }
        catch (IOException ioe) {
            ioe.printStackTrace();
            System.out.println("读取文件时出错：" + musicPath);
        }
        catch (LineUnavailableException lue) {
            lue.printStackTrace();
            System.out.println("音频线路不可用：" + musicPath);
        }
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("播放音乐时出现未知错误：" + musicPath);
        }

    }

}